﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;


namespace DiskGarden
{
	public partial class FrmMain : Form
	{
		RootNode _root;
		RootNode root
		{
			get { return _root; }
			set
			{
				_root = value;
				_root.NodeAdded += new NodeEventHandler(root_NodeAdded);
				treeView.DataSource = value;
			}
		}

		string lastOpenedFile = string.Empty;
		Node SelectedNode
		{
			get
			{
				if (treeView.Focused && treeView.SelectedNode != null)
					return treeView.SelectedNode.Tag as Node;
				else if (listView.Focused && listView.FocusedItem != null)
					return listView.FocusedItem.Tag as Node;
				else
					return null;
			}
		}
		Locale locale;

		const string dialogFilter1 = "DiskGarden Catalog .DGC|*.dgc";
		const string dialogFilter2 = "DiskGarden Import/Export Backup XML.GZ|*.xml.gz";

		public FrmMain() : this(null) { }

		public FrmMain(string filename)
		{
			InitializeComponent();
			Localize();
			treeView.ImageList = Icons.ImgList;
			listView.SmallImageList = Icons.ImgList;
			if (string.IsNullOrEmpty(filename) == false && System.IO.File.Exists(filename))
			{
				root = RootNode.LoadFromFile(filename);
				root.UpdateTree(treeView);
				lastOpenedFile = filename;
			}
			else
				root = new RootNode();
		}

		private void Localize()
		{
			locale = Locale.GetInstance();
			mi_AddCategory.Text = miAddCategory.Text = tbtnAddCategory.Text = locale.AddCategory;
			mi_Properties.Text = miProperties.Text = tbtnProperties.Text = locale.Properties;
			mi_AddDisk.Text = miAddDisk.Text = tbtnAddDisk.Text = locale.AddDisk;
			mi_Refresh.Text = miRefresh.Text = locale.Refresh;
			mi_Delete.Text = miDelete.Text = tbtnDelete.Text = locale.Delete;
			miEdit.Text = locale.Edit;
			miExit.Text = locale.Exit;
			miFile.Text = locale.File;
			miFind.Text = tbtnFind.Text = mi_Find.Text = locale.Find;
			miNew.Text = tbtnNew.Text = locale.New;
			miOpen.Text = tbtnOpen.Text = locale.Open;
			miSave.Text = tbtnSave.Text = locale.Save;
			miSaveAs.Text = locale.SaveAs;
			miImportXML.Text = locale.ImportXML;
			miExportXML.Text = locale.ExportXML;
			columnHeaderDate.Text = locale.Modified;
			columnHeaderName.Text = locale.Name;
			columnHeaderSize.Text = locale.Size;
		}


		DateTime lastTimeInfoChanged = DateTime.Now;
		void root_NodeAdded(Node node)
		{
			if (FrmWait.IsStarted() && (DateTime.Now - lastTimeInfoChanged).TotalMilliseconds > 200)
			{
				FrmWait.SetInfo(node.Path);
				lastTimeInfoChanged = DateTime.Now;
			}
		}

		#region FILE HELPERS

		private void NewFile()
		{
			root = new RootNode();
			treeView.Nodes.Clear();
			listView.Items.Clear();
		}

		private void OpenFile(bool importXML)
		{
			if (importXML)
				openDialog.Filter = dialogFilter2;
			else
				openDialog.Filter = dialogFilter1;

			if (openDialog.ShowDialog() == DialogResult.OK)
			{
				//
				DateTime dt = DateTime.Now;
				Trace.WriteLine(dt, "Opening file");
				//
				if (importXML)
					root = RootNode.LoadFromXml(openDialog.FileName);
				else
					root = RootNode.LoadFromFile(openDialog.FileName);
				//
				Trace.WriteLine((DateTime.Now - dt).TotalMilliseconds, "Opening and deserialization time");
				//
				root.UpdateTree(treeView);
				//
				Trace.WriteLine((DateTime.Now - dt).TotalMilliseconds, "Opening with adding to treeView time");
				//
				listView.Items.Clear();
				if (importXML)
					lastOpenedFile = string.Empty;
				else
					lastOpenedFile = openDialog.FileName;
			}
		}

		private void SaveFile()
		{
			if (System.IO.File.Exists(lastOpenedFile))
			{
				//
				DateTime dt = DateTime.Now;
				Trace.WriteLine(dt, "Saving file");
				//
				root.SaveToFile(lastOpenedFile);
				//
				Trace.WriteLine((DateTime.Now - dt).TotalMilliseconds, "Saving time");
			}
			else
			{
				SaveAsFile(false);
			}
		}

		private void SaveAsFile(bool exportXML)
		{
			if (exportXML)
				saveDialog.Filter = dialogFilter2;
			else
				saveDialog.Filter = dialogFilter1;

			if (saveDialog.ShowDialog() == DialogResult.OK)
			{
				//
				DateTime dt = DateTime.Now;
				Trace.WriteLine(dt, "Saving file");
				//
				if (exportXML)
					root.SaveToXml(saveDialog.FileName);
				else
				{
					root.SaveToFile(saveDialog.FileName);
					lastOpenedFile = saveDialog.FileName;
				}
				//
				Trace.WriteLine((DateTime.Now - dt).TotalMilliseconds, "Saving time");
			}
		}

		protected override void OnClosing(CancelEventArgs e)
		{
			base.OnClosing(e);
			if (MessageBox.Show(locale.DoYouWantExit,
								locale.ExitQuestion, MessageBoxButtons.OKCancel,
								MessageBoxIcon.Question) == DialogResult.Cancel)
				e.Cancel = true;
		}

		#endregion

		#region EDIT HELPERS

		private void AddCategory()
		{
			using (FrmAddCategory frm = new FrmAddCategory())
				if (frm.ShowDialog(this) == DialogResult.OK)
				{
					Node newNode = null;
					Node node = SelectedNode;
					if (node != null && node.Type == NodeType.Category)
					{
						newNode = ((CategoryNode)node).AddCategory(frm.InputText);
						node.Sort();
					}
					else
					{
						newNode = root.AddCategory(frm.InputText);
						root.Sort();
					}
					TreeNode treeNode = treeView.FindTreeNode(newNode);
					treeNode.EnsureVisible();
				}
		}

		private void AddDisk()
		{
			FrmAddVolume frm = new FrmAddVolume();
			if (frm.ShowDialog(this) == DialogResult.OK)
			{
				FrmWait.Start(this);
				Node parentNode = this.SelectedNode;
				{   // szukanie Kategorii do ktorej można by wsadzić nowy dysk
					while (parentNode != null && parentNode is CategoryNode == false)
					{
						parentNode = parentNode.Parent;
					}
					if (parentNode is CategoryNode == false)
						parentNode = root;
				}
				treeView.BeginUpdate();
				((CategoryNode)parentNode).AddVolume(frm.Path, frm.VolumeName);
				((CategoryNode)parentNode).Sort();
				treeView.EndUpdate();
				//root.UpdateTree(treeView);
				FrmWait.Stop();
			}
		}

		private bool PropertiesOpen(Node node)
		{
			string oldName = node.Name;
			using (FrmProperties F = new FrmProperties(node))
			{
				if (F.ShowDialog() == DialogResult.OK)
				{
					if (oldName != node.Name)
						node.Parent.Sort();
					return true;
				}
				else return false;
			}
		}

		private void PropertiesClick()
		{
			Node node = SelectedNode;
			if (node == null) return;
			PropertiesOpen(node);
			if (listView.Focused)
				listView.FocusedItem.Text = node.Name;
		}

		private void DeleteSelected()
		{
			Node node = SelectedNode;
			if (node == null) return;

			if (MessageBox.Show(string.Format(locale.DoYouWantDeleteFile, node.Name),
								locale.DeleteQuestion, MessageBoxButtons.OKCancel,
								MessageBoxIcon.Question) == DialogResult.OK)
			{
				node.Parent.RemoveChild(node);
			}
		}

		private void Find(CategoryNode root)
		{
			if (root == null) root = this.root;
			using (FrmSearch frm = new FrmSearch(root))
			{
				if (frm.ShowDialog() == DialogResult.OK)
				{
					TreeNode treeNode;
					if (frm.node is DirectoryNode)
						treeNode = treeView.FindTreeNode(frm.node);
					else
						treeNode = treeView.FindTreeNode(frm.node.Parent);
					if (treeNode != null)
					{
						treeNode.EnsureVisible();
						treeView.SelectedNode = treeNode;
					}
				}
			}
		}

		private void RefreshView()
		{
			if (listView.Focused)
			{
				if (treeView.SelectedNode != null)
					(treeView.SelectedNode.Tag as Node).UpdateFileList(listView);
				else
					listView.Items.Clear();
			}
			else
			{
				root.UpdateTree(treeView);
			}
		}

		#endregion

		#region MainMenu Events

		private void miAddCategory_Click(object sender, EventArgs e) { AddCategory(); }
		private void miAddDisk_Click(object sender, EventArgs e) { AddDisk(); }
		private void miProperties_Click(object sender, EventArgs e) { PropertiesClick(); }
		private void miDelete_Click(object sender, EventArgs e) { DeleteSelected(); }
		private void miFind_Click(object sender, EventArgs e) { Find(root); }
		private void miRefresh_Click(object sender, EventArgs e) { RefreshView(); }

		private void miNew_Click(object sender, EventArgs e) { NewFile(); }
		private void miOpen_Click(object sender, EventArgs e) { OpenFile(false); }
		private void miSaveAs_Click(object sender, EventArgs e) { SaveAsFile(false); }
		private void miSave_Click(object sender, EventArgs e) { SaveFile(); }
		private void miImportXML_Click(object sender, EventArgs e) { OpenFile(true); }
		private void miExportXML_Click(object sender, EventArgs e) { SaveAsFile(true); }
		private void miExit_Click(object sender, EventArgs e) { this.Close(); }

		private void mi_Find_Click(object sender, EventArgs e)
		{
			CategoryNode node = SelectedNode as CategoryNode;
			if (node != null)
				Find(node);
			else
				Find(root);
		}

		#endregion

		#region ListView events
		// Klikniecie na plik lub katalog na ListView
		private void listView_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (listView.SelectedItems.Count > 0)
			{
				statusLabel.Text = (listView.SelectedItems[0].Tag as Node).Path;
			}
		}

		// Aktywowanie (dwukrotne klikniecie) na plik lub katalog na ListView
		private void listView_ItemActivate(object sender, EventArgs e)
		{
			Node obj = listView.FocusedItem.Tag as Node;

			if (obj.IsContainer())
			{
				obj.UpdateFileList(listView);
				foreach (TreeNode N in treeView.SelectedNode.Nodes)
				{
					if (N.Tag == obj)
					{
						treeView.SelectedNode = N;
						N.Expand();
						N.EnsureVisible();
						break;
					}
				}
			}
			else if (obj is FileNode)
			{
				FileNode F = (FileNode)obj;
				if (PropertiesOpen(F))
					listView.SelectedItems[0].Text = F.Name;
			}
		}

		private void listView_KeyUp(object sender, KeyEventArgs e)
		{
			if (listView.SelectedItems.Count > 0 && e.KeyData == Keys.F2)
			{
				listView.LabelEdit = true;
				listView.FocusedItem.BeginEdit();
			}
		}

		private void listView_AfterLabelEdit(object sender, LabelEditEventArgs e)
		{
			if (e.Label != null && e.Label.Trim() != string.Empty)
			{
				((Node)listView.Items[e.Item].Tag).Name = e.Label;
			}
			else
				e.CancelEdit = true;
			listView.LabelEdit = false;
		}

		#endregion

		private void menuNode_Opening(object sender, CancelEventArgs e)
		{
			ContextMenuStrip menu = sender as ContextMenuStrip;
			if (menu != null)
			{
				if (menu.SourceControl == treeView)
				{
					TreeViewHitTestInfo hitTest = treeView.HitTest(treeView.PointToClient(Cursor.Position));
					if (treeView.SelectedNode != hitTest.Node)
						treeView.SelectedNode = hitTest.Node;
				}
				else if (menu.SourceControl == listView)
				{
					if (listView.SelectedItems.Count == 0)
					{
						e.Cancel = true;
						return;
					}
				}
				if (SelectedNode != null)
				{
					mi_AddCategory.Visible = mi_AddDisk.Visible = mi_Line1.Visible = mi_Line2.Visible = mi_Find.Visible = (SelectedNode.Type == NodeType.Category && menu.SourceControl != listView);
					mi_Delete.Visible = mi_Properties.Visible  = true;
				}
				else
				{
					mi_AddCategory.Visible = mi_AddDisk.Visible = mi_Line2.Visible = mi_Find.Visible = true;
					mi_Delete.Visible = mi_Properties.Visible = mi_Line1.Visible = mi_Refresh.Visible = false;
				}
			}
		}

		


	}
}
